LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

计算机图形学⑧

2021/4/22

8.shading3(texture mapping)

8.shading3(texture mapping)

barycentric coordinate(interpolation across triangles)(用重心坐标在三角形内做插值)

为什么我们要做插值?

很多操作在顶点才能操作,希望能在内部得到一个平滑过渡的值

我们能插值什么内容?

纹理的坐标,颜色,法线向量

我们怎么做插值

利用重心坐标!

the definition(定义)

image-20210422180822945

重心坐标定义在一个三角形内,换一个三角形就换一套重心坐标

在三角形ABC形成的平面内的任意一点,都可以表示成为ABC坐标的线性组合(不需要再使用xy坐标系),其中三个系数αβγ之和为1(如果不为1那就不在三角形所在的平面内了)。这αβγ组成的坐标就是重心坐标。但其实我们只需要知道其中两个数,就能求得第三个数。

若这个点在三角形内,那么αβγ必须都为非负数。

image-20210422181631730

所以A点自己的重心坐标就是(1,0,0)啦

image-20210422182918119

这里α的取值就是他对应三角形的面积除以三角形的总面积,其他的也一样。

image-20210422183147101

我们可以很快求得三角形的重心的重心坐标(Soga叫重心坐标原来如此)

image-20210422183458729

简化一下(对计算机来说确实是简化了,但对我不是)就可以求得α和β具体的值(其实就是做叉乘操作)

这个表达式我们没有必要去记忆,因为很好算,我们只需要我们能得到这个重心坐标就行


how to use barycentric coordinate(使用重心坐标)

image-20210422183911971

假设三个点有三个属性(位置,颜色,纹理坐标,法线,深度),就可以用重心坐标把所需要的点插值出来。

如果将空间中的三角形投影到屏幕,那么前后重心坐标的插值结果将不同(已经不是同一个三角形了)

所以我们如果拿到一个三维的三角形,那么我们就应该取他们三维空间中的坐标,然后算这个三角形的插值,然后再放进去,而不能在投影后的三角形中做

applying textures(应用纹理)

image-20210422185637961

对应屏幕上任意一个采样点,我们都能算出这个点插值出来的uv(对应在三角形的位置),在纹理上查询这个点的颜色,我们可以认为纹理定义的就是这个点的漫反射系数(布林冯模型的kd)

,相当于就是把这张图贴在了物体上,同时这个物体也有冯shading 带来的高光。

texture magnification(纹理太小的情况)

假设我们要刷一堵4k的墙,但我们的纹理只有256x256,纹理分辨率太小了怎么办

bilinear interpolation(双线性插值)

image-20210422190550137

图中黑点为纹理,红点为我们的像素,如图所示像素并不是整数

image-20210422191542817

我们找到这四个点,把红点(在四个像素内的坐标范围是0到1)线性插值出来

具体步骤:

把水平的这两对点插值出来,然后得到两个点,再把这两个点进行竖直方向的插值

虽然获得了不错的效果,但还不够完美


bicubic(双三次插值)

取周围十六个点,做三次插值(不是线性的)


所以好质量的东西往往伴随着更大的开销不是吗

texture magnification(纹理太大的情况)

纹理太大的话

image-20210422192655054

远处摩尔纹近处锯齿,走样啦!

那我们可以直接做抗锯齿吗?

当然可以,但是开销不小。

那我们不采样了!那就不会走样了!

mipmap:

允许做range query(范围查询)查到一个区域里面的平均值,算的快,但是近似值,且要求区域是正方形

image-20210422193925163

拿到材质时先把对应的mipmap生成

多出这些图花费了1/3的空间,这样很棒不是吗

image-20210422211459918

(这块有点听不明白)

我们知道一个点映射到纹理上是一块区域,那么我们怎么知道究竟是什么样的区域呢

image-20210422211632684

假设这个像素有边上两个邻居,我们计算一下他到另外两个邻居的长度,然后取较长的那个构造一个正方形,然后这个正方形就是所求的近似区域。(但这不是重点,重点是这个正方形的查询怎么做)

假设原图为4x4,则我们在第二层做mipmap最终会得到一个像素,这个像素就是我们所需要的这个区域的平均值。

image-20210422212251655

所以如图所示,离我们很近这里我们能看到很多细节,所以我们在比较低的层做查询。

离我们特别远的地方,一个像素覆盖的区域就特别大,所以我们要在特别高的层查询,那个时候一个区域才近似是一个像素。

然后我们发现这里的层是离散的,我们算不出1.8层那样的层是什么样的,最终成品说不定我们会看到一条缝,那我们怎么做呢?

插值就行了!

triinear interpolation(三线性插值)

image-20210422212740074

先找第一层,再找第二层,把这两层做双线性插值,把这两层对应的插值算出来,然后再层与层之间再做一次插值

image-20210422213459234

因为本身开销很小,所以游戏画面中很喜欢使用这个技术

mipmap limitation

mipmap并不是在所有情况都能解决问题的

image-20210422213653125

在远处会出现overblur(过分模糊)

因为三线性插值只能查询正方形区域的平均值

所以又有一个办法可以改进三线性插值带来的问题

anisotropic filtering(各向异性过滤)

image-20210422214045919

(在游戏中大量采用)(需要三倍开销)

能解决一部分问题,得到更准确的结果,但对于图中这种斜着的矩形还是很难计算。


好晚才写完,今天效率超级低4.22 21:45